<!DOCTYPE html>
<html lang="en">

<head>
	<!--
	Copyright (c) 2013-2021 Antoine Martin <antoine@xpra.org>
	Copyright (c) 2014 Joshua Higgins <josh@kxes.net>
	Licensed under MPL 2.0
	-->

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
	<!-- Bootstrap core CSS -->
	<link href="css/bootstrap.css" rel="stylesheet">
	<!-- Custom styles for this template -->
	<link href="css/signin.css" rel="stylesheet">
	<title>Xpra HTML5 Client</title>
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="mobile-web-app-capable" content="yes">
	<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
	<link rel="icon" type="image/png" href="favicon.png">

	<script src="js/lib/es6-shim.js"></script>
	<script src="js/lib/AudioContextMonkeyPatch.js"></script>

	<script src="js/lib/jquery.js"></script>
	<script src="js/Utilities.js"></script>
	<script src="js/MediaSourceUtil.js"></script>
	<script src="js/lib/aurora/aurora.js"></script>
	<!--
	<script src="js/lib/aurora/mp3.js"></script>
	<script src="js/lib/aurora/flac.js"></script>
	<script src="js/lib/aurora/aac.js"></script>
	-->
</head>

<body>
    <div class="container">

		<form class="form-signin" action="./index.html">

	  	  <img src="icons/xpra-logo.png" alt="xpra logo">
		  <h2 class="form-signin-heading">Xpra HTML5 Client</h2>

		  <div id="alert-disconnect" class="alert alert-info" role="alert" style="display:none;">
		  	<p>You were disconnected for the following reason:</p>
		  	<p><span id="disconnect-reason"></span></p>
		  </div>

		  <div class="form-group form-inline">
			<label class="sr-only" for="server">Server</label>
			<input title="Server" type="text" class="form-control" id="server" placeholder="Server" maxlength="256">
			<label class="sr-only" for="port">Port</label>
			<input title="Port" type="text" class="form-control" id="port" placeholder="Port" size="5" maxlength="5">
			<br>
			<label class="sr-only" for="username">Username</label>
			<input title="Username" type="text" class="form-control" id="username" autocomplete="username" placeholder="Username" size="16" maxlength="256">
			<label class="sr-only" for="password">Password</label>
			<input title="Password" type="password" class="form-control" id="password"  autocomplete="current-password" placeholder="Password" size="16" maxlength="256">
			<br>
			<div class="security-box">
			  	<span id="ssl-span"><input type="checkbox" id="ssl"> Secure Sockets</span>
			  	<span id="insecure-span"><input type="checkbox" id="insecure"> Insecure plain-text passwords</span>
			  	<br />
			  	<span id="encryption-span"><input type="checkbox" id="encryption"> AES</span>
				<span id="encryption-key-span"><input type="password" class="form-control" id="key" autocomplete="on" placeholder="AES-KEY" size="32" maxlength="256"></span>
			</div>

			<div class="panel-group">
			  <ul class="list-style-none action">
				<li id="action_connect_group">
					<label><input type="radio" name="action" class="radiobox" value="connect" id="action_connect" checked="checked"> Connect:</label>
					<input title="display" type="text" class="form-control command" id="display" placeholder="Display (optional)" size="20" maxlength="256">
					<select id="select_display" style="display:none;"></select><span id="select_display_warning" class="warning"></span>
				</li>
				<li id="action_start_group">
					<div style="display:inline-block;vertical-align:top;">
						<label><input type="radio" name="action" class="radiobox" value="start" id="action_start" checked="checked"> Start Command:</label>
						<input title="command" type="text" class="form-control command" id="start_command" placeholder="Command" size="20" maxlength="256">
					</div>
					<div style="display:inline-block;">
						<select id="command_category" style="display:none;"></select>
						<img class="command-icon" id="command_category_icon" alt="desktop command category icon" src="./icons/noicon.png" />
						<br />
						<select id="command_entry" style="display:none;"></select>
						<img class="command-icon" id="command_entry_icon" alt="desktop command icon" src="./icons/noicon.png" />
					</div>
				</li>
				<li id="action_start_desktop_group">
					<label><input type="radio" name="action" class="radiobox" value="start-desktop" id="action_start_desktop" checked="checked"> Start Desktop:</label>
					<input title="desktop command" type="text" class="form-control command" id="start_desktop_command" placeholder="Desktop Command" size="20" maxlength="256">
					<img class="command-icon" id="desktop_entry_icon" alt="desktop command icon" src="./icons/noicon.png" />
					<select id="desktop_entry" style="display:none;"></select><span id="desktop_entry_warning" class="warning"></span>
				</li>
				<li id="action_shadow_group">
					<label><input type="radio" name="action" class="radiobox" value="shadow" id="action_shadow" checked="checked"> Shadow:</label>
					<input title="display" type="text" class="form-control command" id="shadow_display" placeholder="Display (optional)" size="20" maxlength="256">
					<select id="select_shadow_display" style="display:none;"></select><span id="select_shadow_display_warning" class="warning"></span>
				</li>
			  </ul>
			</div>
		  </div>

		  <div class="form-group">
		  	<a class="btn btn-lg btn-success" role="button" onclick="doConnect();">Connect</a>
		  	<a class="btn btn-lg btn-success" role="button" onclick="doConnectURI();">Client URI</a>
		  	<a class="btn btn-lg btn-success" role="button" onclick="downloadConnectionFile();">Connection File</a>
		  </div>

		  <div class="panel-group" role="tablist">
			<div class="panel panel-default">
			  <div id="expandopts" class="panel-heading" role="tab">
				<h4 class="panel-title">Advanced options</h4>
			  </div>

			  <div id="hiddenopts" class="panel-collapse collapse in" role="tabpanel" style="display:none;">
				<ul class="list-group">

				  <li class="list-group-item">
					<select id="bandwidth_limit">
					  <option value="0">None</option>
					  <option value="100000000">100Mbps</option>
					  <option value="10000000">10Mbps</option>
					  <option value="1000000">1Mbps</option>
					</select>
					Bandwith Constraint
				  </li>

				  <li class="list-group-item">
					<select id="encoding">
					  <option value="auto">Automatic</option>
					  <option value="jpeg">JPEG</option>
					  <option value="png">PNG</option>
					  <option value="rgb">Raw RGB</option>
					</select>
					Encoding
				  </li>

				  <li class="list-group-item">
					<select id="keyboard_layout">
					  <option value="us">English USA</option>
					  <option value="gb">United Kingdom</option>
					  <option value="fr">France</option>
					  <option value="de">Germany</option>
					  <option value="es">Spain</option>
					  <option value="" disabled>----------------</option>
					  <option value="ad">Andorra</option>
					  <option value="af">Afghanistan</option>
					  <option value="al">Albania</option>
					  <option value="ara">Arabic</option>
					  <option value="am">Armenia</option>
					  <option value="az">Azerbaijan</option>
					  <option value="bd">Bangladesh</option>
					  <option value="by">Belarus</option>
					  <option value="be">Belgium</option>
					  <option value="bt">Bhutan</option>
					  <option value="ba">Bosnia</option>
					  <option value="br">Brazil</option>
					  <option value="bg">Bulgaria</option>
					  <option value="kh">Cambodia</option>
					  <option value="ca">Canada</option>
					  <option value="cn">China</option>
					  <option value="cd">Congo,</option>
					  <option value="hr">Croatia</option>
					  <option value="cz">Czechia</option>
					  <option value="dk">Denmark</option>
					  <option value="epo">Esperanto</option>
					  <option value="ee">Estonia</option>
					  <option value="et">Ethiopia</option>
					  <option value="ir">Iran</option>
					  <option value="iq">Iraq</option>
					  <option value="fo">Faroe</option>
					  <option value="fi">Finland</option>
					  <option value="fr">France</option>
					  <option value="ge">Georgia</option>
					  <option value="gh">Ghana</option>
					  <option value="gr">Greece</option>
					  <option value="gn">Guinea</option>
					  <option value="hu">Hungary</option>
					  <option value="is">Iceland</option>
					  <option value="in">India</option>
					  <option value="ie">Ireland</option>
					  <option value="il">Israel</option>
					  <option value="it">Italy</option>
					  <option value="jp">Japan</option>
					  <option value="kz">Kazakhstan</option>
					  <option value="kr">Korea,</option>
					  <option value="kg">Kyrgyzstan</option>
					  <option value="latam">Latin</option>
					  <option value="lv">Latvia</option>
					  <option value="la">Laos</option>
					  <option value="lt">Lithuania</option>
					  <option value="mao">Maori</option>
					  <option value="mk">Macedonia</option>
					  <option value="mv">Maldives</option>
					  <option value="ml">Mali</option>
					  <option value="mt">Malta</option>
					  <option value="mn">Mongolia</option>
					  <option value="me">Montenegro</option>
					  <option value="ma">Morocco</option>
					  <option value="mm">Myanmar</option>
					  <option value="np">Nepal</option>
					  <option value="nl">Netherlands</option>
					  <option value="ng">Nigeria</option>
					  <option value="no">Norway</option>
					  <option value="pk">Pakistan</option>
					  <option value="pl">Poland</option>
					  <option value="pt">Portugal</option>
					  <option value="ro">Romania</option>
					  <option value="ru">Russia</option>
					  <option value="sn">Senegal</option>
					  <option value="rs">Serbia</option>
					  <option value="sk">Slovakia</option>
					  <option value="si">Slovenia</option>
					  <option value="za">South Africa</option>
					  <option value="lk">Sri Lanka</option>
					  <option value="se">Sweden</option>
					  <option value="ch">Switzerland</option>
					  <option value="sy">Syria</option>
					  <option value="tw">Taiwan</option>
					  <option value="tj">Tajikistan</option>
					  <option value="tz">Tanzania</option>
					  <option value="th">Thailand</option>
					  <option value="tr">Turkey</option>
					  <option value="tm">Turkmenistan</option>
					  <option value="ua">Ukraine</option>
					  <option value="uz">Uzbekistan</option>
					  <option value="vn">Vietnam</option>
					</select>
					Keyboard Layout
				  </li>
				  <li class="list-group-item keyboard">
				  	<input type="checkbox" id="keyboard"> <span>On-screen keyboard</span>
				  </li>

				  <li class="list-group-item clipboard">
				  	<input type="checkbox" id="clipboard"> <span>Clipboard sharing</span>
				  </li>
				  <li class="list-group-item printing">
				  	<input type="checkbox" id="printing"> <span>Printing</span>
				  </li>
				  <li class="list-group-item file_transfer">
				  	<input type="checkbox" id="file_transfer"> <span>File transfers</span>
				  </li>
				  <li class="list-group-item sound">
					<input type="checkbox" id="sound"> <span>Audio forwarding, codec: </span>
					<select id="audio_codec">
				  	</select>
				  	<input type="hidden" id="ignore_audio_blacklist" value="" />
				  </li>
				  <li class="list-group-item exit_with_children">
				  	<input type="checkbox" id="exit_with_children"> <span>Terminate server when command exits</span>
				  </li>
				  <li class="list-group-item exit_with_client">
				  	<input type="checkbox" id="exit_with_client"> <span>Terminate server when client disconnects</span>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="sharing"> <span>Share session</span>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="steal"> <span>Steal session from existing client</span>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="reconnect"> <span>Re-connect automatically to the session</span>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="swap_keys"> <span>Swap command and control key</span>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="scroll_reverse_y"> <span>Reverse vertical scrolling</span>
				  	<input type="checkbox" id="scroll_reverse_x"> <span>Reverse horizontal scrolling</span>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="floating_menu"> <span>Floating Menu</span>, <input type="checkbox" id="autohide"> <span>Auto Hide</span>, <input type="checkbox" id="clock"> <span>Server clock</span>
				  	<br />
					<li class="list-group-item">
					  Menu position:
					  <select id="toolbar_position">
						<option value="top-left">Top Left</option>
						<option value="top">Top</option>
						<option value="top-right">Top Right</option>
					  </select>
				  </li>
				  <li class="list-group-item">
				  	<input type="checkbox" id="video"> <span>Video <input type="checkbox" id="mediasource_video"> Native decoding</span>
				  </li>
				  <li class="list-group-item">
				  	<span>Server Path:</span>
					<input title="path" type="text" class="form-control" id="path" placeholder="" size="16" maxlength="256">
				  </li>
				  <li class="list-group-item">
					<span>Client Screen Width:</span>
					<input title="override_width" type="text" class="form-control" id="override_width" size="16" maxlength="256">
				  </li>
				  <li class="list-group-item">
				  	<span>Debugging</span>:<br/>
				  	<input type="checkbox" id="debug_main"> <span>Main</span>,
				  	<input type="checkbox" id="debug_keyboard"> <span>keyboard</span>,
				  	<input type="checkbox" id="debug_geometry"> <span>geometry</span>,
				  	<input type="checkbox" id="debug_mouse"> <span>mouse</span>,
				  	<input type="checkbox" id="debug_clipboard"> <span>clipboard</span>
				  	<input type="checkbox" id="debug_draw"> <span>draw</span>,
				  	<input type="checkbox" id="debug_audio"> <span>audio</span>,
				  	<input type="checkbox" id="debug_network"> <span>network</span>
				  </li>
				</ul>
			  </div>
			</div>
		  </div>

		</form>



	</div> <!-- /container -->
    <div class="bg-image"></div>

<script>

const VALUE_PROPERTIES = ["server", "port", "path", "username", "password", "key",
					"bandwidth_limit", "encoding", "keyboard_layout", "audio_codec", "toolbar_position",
					"display", "shadow_display", "override_width",
					];
const BOOLEAN_PROPERTIES = ["keyboard", "clipboard", "printing", "file_transfer",
		"sound", "ignore_audio_blacklist",
		"exit_with_children", "exit_with_client",
		"sharing", "steal", "reconnect", "swap_keys",
		"scroll_reverse_x", "scroll_reverse_y",
		"video", "mediasource_video",
		"ssl", "insecure", "encryption",
		"floating_menu", "autohide", "clock",
		"debug_main", "debug_keyboard", "debug_geometry", "debug_mouse", "debug_clipboard", "debug_draw", "debug_audio", "debug_network",
	];
const FILE_PROPERTIES = ["server", "port", "username", "password",
		"exit_with_children", "exit_with_client",
		"sharing", "swap_keys"];
const FILE_TRANSLATION = {"server" : "host"};


function add_prop(prop, value, first) {
	if (Utilities.hasSessionStorage()) {
		//we're using sessionStorage, no need for URL
		if (value===null || value==="undefined") {
			sessionStorage.removeItem(prop);
		}
		else {
			sessionStorage.setItem(prop, value);
		}
		return "";
	}
	if (value===null || value==="undefined") {
		value = "";
	}
	let sep = "&";
	if (first) {
		sep = "?";
	}
	return sep+prop+"="+encodeURIComponent(""+value);		//ie: "&port=10000"
}

function doConnect() {
	let url = "./index.html" + add_prop("submit", true, true) + get_URL_action() + get_URL_props();
	window.location = url;
}

function doConnectURI() {
	let url = "xpraws://";
	const ssl = document.getElementById("ssl").checked;
	if (ssl) {
		url = "xprawss://";
	}
	const username = document.getElementById("username").value;
	if (username) {
		url += username+"@";
	}
	url += document.getElementById("server").value;
	const port = document.getElementById("port").value;
	if (port) {
		url += ":"+port;
	}
	url += "/";
	url += get_URL_action() + get_URL_props();
	window.location = url;
}

function downloadConnectionFile() {
	const filename = (document.getElementById("server").value || "session")+".xpra";
	let data = "autoconnect=true\n";
	//set a mode:
	const ssl = document.getElementById("ssl").checked;
	if (ssl) {
		data += "mode=wss\n";
	}
	else {
		data += "mode=ws\n";
	}
	for (let i = 0; i < FILE_PROPERTIES.length; i++) {
		const prop = FILE_PROPERTIES[i];
		const prop_name = FILE_TRANSLATION[prop] || prop;
		const value = document.getElementById(prop).value;
		if (value!=="") {
			data += prop_name+"="+value+"\n";
		}
	}
	//convert debug switches to a list of debug categories:
	let debug = "";
	const DEBUG_CATEGORIES = ["main", "keyboard", "geometry", "mouse", "clipboard", "draw", "audio", "network"];
	for (let i = 0; i < DEBUG_CATEGORIES.length; i++) {
		let category = DEBUG_CATEGORIES[i];
		const el = document.getElementById("debug_"+category);
		if (el && el.checked) {
			//"main" enables "client" debugging:
			let s = ((category=="main") ? 'client' : category);;
			if (debug) {
				debug += ","+category;
			}
			else {
				debug = category;
			}
		}
	}
	if (debug) {
		data += "debug="+debug+"\n";
	}
	Utilities.saveFile(filename, data, {type : "text/plain"});
}

function get_visible_value(entry, select) {
	let entry_widget = document.getElementById(entry);
	if (entry_widget.style.visibility !== "hidden" || entry_widget.style.visibility !== "collapse") {
		return entry_widget.value;
	}
	let select_widget = document.getElementById(select);
	if (select_widget.style.visibility !== "hidden" || select_widget.style.visibility !== "collapse") {
		return select_widget.value;
	}
	return "";
}

function get_URL_action() {
	let url = "";
	let start = "";
	let display = "";
	let action = "";
	if (document.getElementById("action_connect").checked) {
		action = "connect";
		display = get_visible_value("display", "select_display")
	}
	else if (document.getElementById("action_start").checked) {
		action = "start";
		start = get_visible_value("start_command", "command_entry");
	}
	else if (document.getElementById("action_start_desktop").checked) {
		action = "start-desktop";
		start = get_visible_value("start_desktop_command", "desktop_entry");
	}
	else if (document.getElementById("action_shadow").checked) {
		action = "shadow";
		display = get_visible_value("shadow_display", "select_shadow_display");
	}
	if (action) {
		url += add_prop("action", action);
	}
	if (start) {
		url += add_prop("start", start);
	}
	if (display) {
		url += add_prop("display", display);
	}
	return url;
}

function get_URL_props() {
	let url = "";
	for (let i = 0; i < VALUE_PROPERTIES.length; i++) {
		const prop = VALUE_PROPERTIES[i];
		const value = document.getElementById(prop).value;
		url += add_prop(prop, value);
	}
	for (let i = 0; i < BOOLEAN_PROPERTIES.length; i++) {
		const prop = BOOLEAN_PROPERTIES[i];
		url += add_prop(prop, document.getElementById(prop).checked);
	}
	return url;
}


function fill_form(default_settings) {
	const getparam = function(prop) {
		let v = Utilities.getparam(prop);
		if (v==null && prop in default_settings) {
			v = default_settings[prop];
		}
		return v;
	};
	const getboolparam = function(prop, default_value) {
		let v = Utilities.getparam(prop);
		if (v==null && prop in default_settings) {
			v = default_settings[prop];
		}
		if (v===null) {
			return default_value;
		}
		return ["true", "on", "1", "yes", "enabled"].indexOf(String(v).toLowerCase())!==-1;
	};

	const disconnect_reason = getparam("disconnect") || null;
	if(disconnect_reason) {
		document.getElementById("alert-disconnect").style.display = "block";
		document.getElementById("disconnect-reason").innerText = disconnect_reason;
	}

	//Populate the form:
	const url = window.location.href;
	const link = document.createElement('a');
	link.setAttribute('href', url);
	let pathname = link.pathname;
	if (pathname && pathname.endsWith("connect.html")) {
		pathname = pathname.substring(0, pathname.length-"connect.html".length);
	}
	if (pathname && pathname=="/") {
		pathname = "";
	}
	var path = getparam("path")
	if (path && path.endsWith("/index.html")) {
		path = path.substr(0, path.lastIndexOf("/"));
	}
	const https = document.location.protocol=="https:";
	var protocol_port=80;
	if(https){
		protocol_port=443;
	}
	document.getElementById("server").value = getparam("server") || link.hostname;
	document.getElementById("port").value = getparam("port") || link.port || protocol_port;
	document.getElementById("path").value = path || pathname;
	document.getElementById("username").value = getparam("username") || "";

	const override_width = getparam("override_width");
	if (override_width) {
		document.getElementById("override_width").value = override_width;
	} else {
		document.getElementById("override_width").placeholder = window.innerWidth;
	}

	const ssl = getboolparam("ssl", https);
	const insecure = getboolparam("insecure", false);
	$('input#ssl').prop("checked", ssl);
	$('input#insecure').prop("checked", insecure);
	const ssl_input = document.getElementById("ssl");
	const insecure_input = document.getElementById("insecure");
	const encryption_input = document.getElementById("encryption");
	const key_input = document.getElementById("key");
	const has_session_storage = Utilities.hasSessionStorage();
	$('span#encryption-key-span').hide();
	encryption_input.onchange = function() {
		if (encryption_input.checked) {
			ssl_input.checked = false;
			$('span#encryption-key-span').show();
			if (!key_input.value) {
				key_input.focus();
			}
		}
		else {
			$('span#encryption-key-span').hide();
		}
	};
	if (!has_session_storage) {
		//passwords would be sent on URL,
		//so show insecure checkbox whenever ssl is off:
		ssl_input.onchange = function() {
			$('input#password').prop("disabled", !has_session_storage && !ssl_input.checked && !insecure_input.checked);
			if (ssl_input.checked) {
			   	$('span#insecure-span').hide();
			   	encryption_input.checked = false;
			}
			else {
			   	$('span#insecure-span').show();
			}
		}
	}
	else {
		//local storage makes this secure
	   	$('span#insecure-span').hide();
		ssl_input.onchange = function() {
			if (ssl_input.checked) {
			   	encryption_input.checked = false;
				$('span#encryption-key-span').hide();
			}
		}
	}
	$('input#password').prop("disabled", !has_session_storage && !ssl_input.checked && !insecure_input.checked);
	insecure_input.onchange = function() {
		$('input#password').prop("disabled", !has_session_storage && !ssl_input.checked && !insecure_input.checked);
	};

	const action = getparam("action") || "";
	if(action=="shadow") {
		document.getElementById("action_shadow").checked = true;
	}
	else if(action=="start-desktop") {
		document.getElementById("action_start_desktop").checked = true;
	}
	else if(action=="start") {
		document.getElementById("action_start").checked = true;
	}
	else {
		document.getElementById("action_connect").checked = true;
	}
	const start = getparam("start") || "";


	function get_host_address(skip_credentials) {
		let url = "http";
		if (document.getElementById("ssl").checked) {
			url += "s";
		}
		url += "://";
		if (!skip_credentials) {
			const username = document.getElementById("username").value;
			if (username) {
				url += username+"@";
			}
		}
		const server = document.getElementById("server").value
		if (!server) {
			//nothing we can do
			error_fn("no server address")
			return;
		}
		url += server;
		const port = document.getElementById("port").value;
		const iport = parseInt(port) || 0;
		if (port && !iport) {
			error_fn("invalid port number '"+port+"'");
			return;
		}
		if (iport) {
			url += ":"+port;
		}
		const path = document.getElementById("path").value;
		if (path) {
			if (!path.startsWith("/")) {
				url += "/";
			}
			url += path;
		}
		return url;
	}

	function json_action(uri, success_fn, error_fn) {
		const url = get_host_address()+uri;
		Utilities.json_action(url, success_fn, error_fn);
	}

	const command_category_icon = document.getElementById("command_category_icon");
	const command_category = document.getElementById("command_category");
	const command_entry_icon = document.getElementById("command_entry_icon");
	const command_entry = document.getElementById("command_entry");
	function load_icon(icon, src) {
		const url = get_host_address(true)+src;
		icon.onload = function() {
			Utilities.log("loaded icon", url);
		};
		icon.onerror  = function(e) {
			Utilities.error("error loading icon", url, ":", e);
		};
		icon.onabort = function(e) {
			Utilities.error("aborted loading icon", url, ":", e);
		};
		icon.src = url;
	}
	function command_entry_changed() {
		var cc = command_category.options[command_category.selectedIndex].innerHTML;
		var c = command_entry.options[command_entry.selectedIndex].innerHTML;
		Utilities.log("command_category=", cc, ", command_entry=", c);
		load_icon(command_entry_icon, "/MenuIcon/"+cc+"/"+c);
		$('#command_entry_icon').show();
	}
	command_entry.addEventListener("change", command_entry_changed);
	function command_category_changed() {
		var cc = command_category.options[command_category.selectedIndex].innerHTML;
		Utilities.log("command_category=", cc);
		load_icon(command_category_icon, "/MenuIcon/"+cc);
		$('#command_category_icon').show();
	}
	command_category.addEventListener("change", command_category_changed);

	function init_command_menu() {
		$('#command_category_icon').hide();
		$('#command_entry_icon').hide();
		json_action("/Menu",
		function(xhr, response) {
			let categories = Object.keys(response);
			//find the category matching "start":
			let default_start = start || "xterm";
			let current_category = "";
			for (let c in categories) {
				let category = categories[c];
				let entries = response[category].Entries;
				for (let e in entries) {
					let entry = entries[e];
					let command_exec = entry.TryExec || entry.Exec;
					if (default_start==command_exec) {
						current_category = category;
					}
				}
			}
			function populate_commands() {
				let selected_category = command_category.value;
				let entries = response[selected_category].Entries;
				command_entry.innerText = null;
				for (let e in entries) {
					let entry = entries[e];
					let command_exec = entry.TryExec || entry.Exec;
					if (default_start==command_exec) {
						$('select#command_entry').append('<option selected="selected" value="'+command_exec+'">'+entry.Name+'</option>');
					}
					else {
						$('select#command_entry').append('<option value="'+command_exec+'">'+entry.Name+'</option>');
					}
				}
				$('select#command_entry').show();
				$('#start_command').hide();
				command_entry_changed();
			}
			command_category.addEventListener("change", populate_commands);
			command_category.innerText = null;
			for (let c in categories) {
				let category = categories[c];
				if (category==current_category) {
					$('select#command_category').append('<option selected="selected">'+category+'</option>');
				}
				else {
					$('select#command_category').append('<option>'+category+'</option>');
				}
			}
			command_category_changed();
			$('select#command_category').show();
			populate_commands();
			command_entry_changed();
	    },
		function(error) {
			$('select#command_category').hide();
			$('select#command_entry').hide();
			$('#start_command').show();
		}
		);
	};

	const desktop_entry_icon = document.getElementById("desktop_entry_icon");
	const desktop_entry = document.getElementById("desktop_entry");
	function desktop_entry_changed() {
		var de = desktop_entry.options[desktop_entry.selectedIndex].innerHTML;
		Utilities.log("desktop_session=", de);
		load_icon(desktop_entry_icon, "/DesktopMenuIcon/"+de);
	}
	desktop_entry.addEventListener("change", desktop_entry_changed);

	function init_desktop_menu() {
		$('#desktop_entry_icon').hide();
		json_action("/DesktopMenu", function(xhr, response) {
			var desktop_sessions = Object.keys(response);
			desktop_entry.innerText = null;
			let default_start_desktop = start;
			if (!default_start_desktop) {
				const PDE = ["xfce", "xfce session", "openbox", "gnome"];
				for (let p in PDE) {
					let de = PDE[p];
					for (let d in desktop_sessions) {
						let desktop_session = desktop_sessions[d];
						if (desktop_session.toLowerCase()==de) {
							let attributes = response[desktop_session];
							default_start_desktop = attributes.TryExec || attributes.Exec;
							break;
						}
					}
					if (default_start_desktop) {
						break;
					}
				}
			}
			for (let d in desktop_sessions) {
				let desktop_session = desktop_sessions[d];
				let attributes = response[desktop_session];
				let command_exec = attributes.TryExec || attributes.Exec;
				let selected='';
				if (default_start_desktop && default_start_desktop==command_exec) {
					selected=' selected="selected" ';
					default_start_desktop = null;
				}
				$('select#desktop_entry').append('<option'+selected+' value="'+command_exec+'">'+
					desktop_session+
					'</option>');
			}
			desktop_entry_changed();
			$('select#desktop_entry').show();
			$('#desktop_entry_icon').show();
			$('#start_desktop_command').hide();
	    },
		function(error) {
			$('select#desktop_entry').hide();
			$('#start_desktop_command').show();
		});
	};

	const display = getparam("display") || "";
	function init_shadow_display() {
		json_action("/Displays", function(xhr, response) {
			var displays = Object.keys(response);
			const select_shadow_display = document.getElementById("select_shadow_display");
			select_shadow_display.innerText = null;
			for (let d in displays) {
				let display_option = displays[d];
				let label = display_option;
				let selected = "";
				let attr = response[display_option];
				if (attr && attr.wmname) {
					label = attr.wmname+" on "+display_option;
				}
				if (display==display_option) {
					selected = ' selected="selected" ';
				}
				$('select#select_shadow_display').append('<option'+selected+'>'+label+'</option>');
			}
			if (displays.length==0) {
				$('span#select_shadow_display_warning').show();
				$('span#select_shadow_display_warning').text("no displays found");
			}
			else {
				$('span#select_shadow_display_warning').hide();
				$('span#select_shadow_display_warning').text("");
			}
			$('select#select_shadow_display').show();
			$('#shadow_display').hide();
	    },
		function(error) {
			$('select#select_shadow_display').hide();
			$('#shadow_display').show();
		});
	}

	function init_connect_display() {
		json_action("/Sessions", function(xhr, response) {
			var sessions = Object.keys(response);
			const select_display = document.getElementById("select_display");
			select_display.innerText = null;
			let count = 0;
			for (let s in sessions) {
				let session = sessions[s];
				let attributes = response[session];
				let session_type = attributes["session-type"];
				if (session_type=="proxy") {
					//cannot attach to a proxy
					continue;
				}
				let session_string = "";
				if (attributes["session-name"]) {
					session_string = attributes["session-name"]+" ";
				}
				session_string += session;
				if (attributes.username) {
					session_string += " ("+attributes.username+")";
				}
				let selected='';
				if (display==session) {
					selected=' selected="selected" ';
				}
				$('select#select_display').append('<option'+selected+' value='+session+'>'+session_string+'</option>');
				count += 1;
			}
			if (count==0) {
				$('span#select_display_warning').show();
				$('span#select_display_warning').text("no sessions found");
			}
			else {
				$('span#select_display_warning').hide();
				$('span#select_display_warning').text("");
			}
			$('select#select_display').show();
			$('#display').hide();

			function display_populate_username() {
				//populate the username if we have it
				let session = select_display.value;
				if (session) {
					let attributes = response[session];
					if (attributes && attributes.username) {
						document.getElementById("username").value = attributes.username;
					}
				}
			}

			select_display.onchange = display_populate_username();
			display_populate_username();
	    },
		function(error) {
			$('select#select_display').hide();
			$('#display').show();
		});
	}


	function show_mode(is_proxy) {
		Utilities.debug("show_mode(", is_proxy, ")");
		if (is_proxy) {
			//show all options:
			$('#action_connect_group').show();
			$('#action_start_group').show();
			$('#action_start_desktop_group').show();
			$('#action_shadow_group').show();
			//(re)populate the drop down menus:
			init_connect_display();
			init_command_menu();
			init_desktop_menu();
			init_shadow_display();
		}
		else {
			//only attach is possible, select it and hide everything:
			$("#action_connect").prop("checked", true);
			$('#action_connect_group').hide();
			$('#action_start_group').hide();
			$('#action_start_desktop_group').hide();
			$('#action_shadow_group').hide();
			$('#command_category_icon').hide();
			$('#command_entry_icon').hide();
			$('#desktop_entry_icon').hide();
		}
	}
	function init_mode() {
		json_action("/Info", function(xhr, response) {
			Utilities.log("/Info=", response);
			let mode = response.mode || "";
			if (mode.indexOf("seamless")>=0 || mode.indexOf("desktop")>=0 || mode.indexOf("shadow")>=0) {
				show_mode(false);
			}
			else {
				show_mode(true);
			}
	    },
		function(error) {
			show_mode(true);
		});
	}
	init_mode();

	let target_changed_timer = 0;
	let ajax_delay = 2000;
	let watched_elements = ["server", "port", "ssl", "encryption"];
	let host_address = "";
	for (var i=0, l=watched_elements.length; i<l; i++) {
		let watched_element = watched_elements[i];
		let el = $('#'+watched_element);
		function cancel_changed_timer() {
		    if (target_changed_timer) {
			    clearTimeout(target_changed_timer);
				target_changed_timer = 0;
			}
		}
		function host_address_changed() {
			cancel_changed_timer();
			const url = get_host_address();
			if (url!=host_address) {
				host_address = url;
				Utilities.debug("host address changed to", url);
				init_mode();
			}
		}
		el.on("change", function() {
			Utilities.log(watched_element, "changed");
			host_address_changed();
		});
		el.on("paste", function() {
			Utilities.log(watched_element, "pasted");
			host_address_changed();
		});
		el.on("keyup", function() {
			Utilities.log(watched_element, "key event");
			cancel_changed_timer();
			target_changed_timer = setTimeout(host_address_changed, ajax_delay);
		});
		el.on("keydown", function() {
			cancel_changed_timer();
		});
	}

	function set_exit_actions(disabled) {
		const opacity = disabled ? 0.6 : 1;
		$('input#exit_with_children').prop("disabled", disabled);
	   	$('input#exit_with_client').prop("disabled", disabled);
	   	$('li.exit_with_children span').css("opacity", opacity);
	   	$('li.exit_with_client span').css("opacity", opacity);
	   	if (disabled) {
		   	$('input#exit_with_children').prop("checked", false);
		   	$('input#exit_with_client').prop("checked", false);
	   	}
	}
	$(document).on('click', '[name="action"]', function() {
		const action = $(this).val();
		set_exit_actions(action=="connect");
	});
	$('input:radio[value="'+action+'"]').click();

	const encoding = getparam("encoding") || "auto";
	document.getElementById('encoding').value = encoding;

	let bandwidth_limit = getparam("bandwidth_limit");
	if(bandwidth_limit==null) {
		const ci = Utilities.getConnectionInfo();
		if (ci) {
			bandwidth_limit = ci["downlink"];
		}
	}
	document.getElementById('bandwidth_limit').value = bandwidth_limit || 0;

	let keyboard_layout = getparam("keyboard_layout");
	if (keyboard_layout==null) {
		keyboard_layout = Utilities.getKeyboardLayout();
	}
	document.getElementById('keyboard_layout').value = keyboard_layout;
	json_action("/favicon.png?echo-headers", function(xhr, response) {
		const headers = Utilities.ParseResponseHeaders(xhr.getAllResponseHeaders());
		Utilities.debug("headers:", headers);
		let lang = headers["Echo-Accept-Language"];
		//ie: lang = "en-gb,en-us;q=0.8,en;q=0.6"
		if (lang) {
			//just the first option:
			Utilities.debug("accept-language:", lang);
			lang = lang.split(",")[0];		//ie: lang="en-gb"
			Utilities.debug("first language:", lang);
			let locale = lang.split("-")[1];
			if (locale) {
				locale = locale.toLowerCase();
				Utilities.debug("request locale:", locale);
				if (locale!=keyboard_layout) {
					keyboard_layout = locale;
					document.getElementById('keyboard_layout').value = keyboard_layout;
				}
			}
		}
	});
	const audio_codec = getparam("audio_codec") || "";
	const audio_codec_select = document.getElementById("audio_codec");
	const ignore_audio_blacklist = getboolparam("ignore_audio_blacklist", false);
	if(ignore_audio_blacklist) {
		$('input#ignore_audio_blacklist').prop("value", true);
	}

	const codecs_supported = MediaSourceUtil.get_supported_codecs(getboolparam("mediasource", true),
			getboolparam("aurora", true),
			getboolparam("http-stream", true),
			ignore_audio_blacklist);
	let best_codec = audio_codec;
	if(!best_codec) {
		best_codec = MediaSourceUtil.get_best_codec(codecs_supported);
	}
	for (let codec_option in codecs_supported) {
		const option = document.createElement("option");
		option.value = codec_option;
		option.textContent = MediaSourceConstants.CODEC_DESCRIPTION[codec_option] || codecs_supported[codec_option];
    	option.selected = (codec_option==best_codec);
	    audio_codec_select.add(option);
	}
	if(!codecs_supported) {
	   	$('input#sound').prop("disabled", true);
	}
	else {
		//enable sound checkbox if the codec is changed:
		audio_codec_select.onchange = function() {
			document.getElementById("sound").checked = true;
		};
	}
	const sound = getboolparam("sound");
	$('input#sound').prop("checked", sound && Object.keys(codecs_supported).length>0);

	const bool_props = ["keyboard", "clipboard", "printing", "file_transfer",
		"encryption",
		"exit_with_children", "exit_with_client",
		"sharing", "steal", "reconnect", "swap_keys",
		"video", "mediasource_video", "floating_menu", "autohide", "clock",
		"scroll_reverse_x", "scroll_reverse_y",
		"debug_main", "debug_keyboard", "debug_geometry", "debug_mouse", "debug_clipboard", "debug_draw", "debug_audio", "debug_network"];
	const default_on = ["steal", "clipboard", "printing", "file_transfer", "reconnect", "floating_menu", "clock", "exit_with_children", "exit_with_client"];
	if (Utilities.is_64bit()) {
		default_on.push("video");
	}
	if (Utilities.isMacOS()) {
		default_on.push("swap_keys");
		default_on.push("scroll_reverse_y");
	}
	if (Utilities.isMobile()) {
		//show the on-screen keyboard by default on mobile:
		default_on.push("keyboard");
	}
	for (let i = 0; i < bool_props.length; i++) {
		const prop = bool_props[i];
		const def = default_on.includes(prop);
		document.getElementById(prop).checked = getboolparam(prop, def);
	}
	function toggle_mediasource_video() {
		$('#mediasource_video').prop("disabled", !video.checked);
	}
	const video = document.getElementById("video");
	video.onchange = toggle_mediasource_video;
	toggle_mediasource_video();

	const floating_menu_checkbox = $("#floating_menu");
	function set_menu_attributes_visibility() {
		if (floating_menu_checkbox.is(':checked')) {
			$("#clock").removeAttr("disabled");
			$("#autohide").removeAttr("disabled");
		}
		else {
		    $("#clock").attr("disabled", true);
		    $("#autohide").attr("disabled", true);
		}
	}
	floating_menu_checkbox.change(set_menu_attributes_visibility);
	set_menu_attributes_visibility();
	let toolbar_position = getparam("toolbar_position") || "top";
	if (toolbar_position) {
		document.getElementById('toolbar_position').value = toolbar_position;
	}

	encryption_input.onchange();

	//this may override default values (ie: terminate flags are off for connect mode):
	set_exit_actions(action=="connect" || action=="");

	$("#expandopts").click(function() {
		$("#hiddenopts").slideToggle();
	});
	//delete session params:
	try {
		sessionStorage.clear();
	}
	catch (e) {
		//ignore
	}
	function submit_if_enter(e) {
	    if (!e) {
	    	const e = window.event;
	    }
	    if (e.keyCode == 13) {
		    e.preventDefault();
		    doConnect();
	    }
	}
	const submit_text_fields = ["server", "port", "username", "password"];
	for (let i = 0; i < submit_text_fields.length; i++) {
		document.getElementById(submit_text_fields[i]).addEventListener("keydown", submit_if_enter);
	}
}

$(document).ready(function() {
	const xhr = new XMLHttpRequest();
	xhr.open("GET", "./default-settings.txt");
	xhr.onload = function() {
		fill_form(Utilities.parseINIString(xhr.responseText));
	};
	xhr.onerror  = function() {
		fill_form({});
	};
	xhr.onabort = function() {
		fill_form({});
	};
	xhr.send();
});

</script>

</body>
</html>
